package cloud.keveri.gateway.core;

import cloud.keveri.base.utils.NetUtils;
import cloud.keveri.gateway.dto.KeveriClientConfigure;
import cloud.keveri.gateway.dto.ServiceDefinition;
import cloud.keveri.gateway.dto.ServiceInstance;
import cloud.keveri.registry.api.InstanceRegisterRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.Properties;

import static cloud.keveri.registry.nacos.def.Const.*;

/**
 * <p>
 * 作者：沈自在
 **/
@Slf4j
@Component
@RequiredArgsConstructor
public class GatewayInitializer implements CommandLineRunner, EnvironmentAware {

    /**
     *
     */
    private final InstanceRegisterRepository instanceRegisterRepository;
    private final DefinitionDefinitionManager definitionDefinitionManager;
    /**
     *
     */
    private Environment environment;

    @Override
    public void setEnvironment(@NonNull Environment environment) {
        this.environment = environment;
    }

    @Override
    public void run(String... args) throws Exception {
        // 1. 初始化配置
        KeveriClientConfigure configure = prepareClientConfigure();

        // 2. 初始化注册中心
        initRegistry(configure);

        // 3.
        ServiceDefinition definition = buildServiceDefinition();

        // 4.
        ServiceInstance instance = buildServiceInstance();

        // 5. 注册
        registerService(definition, instance);

        // 6. 订阅
        subscribeToGatewayServices();
    }

    /**
     *
     */
    private KeveriClientConfigure prepareClientConfigure() {
        KeveriClientConfigure configure = new KeveriClientConfigure();
        configure.setEnv(environment.getProperty("keveri.common.nacos.group"));
        configure.setServerLists(environment.getProperty("keveri.common.nacos.address"));

        Properties props = new Properties();
        props.put(NAMESPACE, environment.getProperty("keveri.common.nacos.namespace"));
        props.put(USERNAME, environment.getProperty("keveri.common.nacos.username"));
        props.put(PASSWORD, environment.getProperty("keveri.common.nacos.password"));
        configure.setProps(props);

        return configure;
    }

    /**
     *
     */
    private void initRegistry(KeveriClientConfigure configure) {
        instanceRegisterRepository.init(configure);
        log.info("[Keveri-Cloud] 初始化注册中心成功 ～～");
    }

    /**
     *
     */
    private ServiceDefinition buildServiceDefinition() {
        return ServiceDefinition.builder()
                .invokerMap(Map.of())
                .uniqueId(environment.getProperty("spring.application.name"))
                .serviceId(environment.getProperty("spring.application.name"))
                .build();
    }

    /**
     *
     */
    private ServiceInstance buildServiceInstance() {
        String localIp = NetUtils.getLocalIp();
        String port = environment.getProperty("server.port");
        assert port != null;
        return ServiceInstance.builder()
                .serviceInstanceId(localIp + ":" + port)
                .ip(localIp)
                .port(Integer.parseInt(port))
                .registerTime(System.currentTimeMillis())
                .build();
    }

    /**
     *
     */
    private void registerService(ServiceDefinition definition, ServiceInstance instance) {
        instanceRegisterRepository.register(definition, instance);
    }

    /**
     *
     */
    private void subscribeToGatewayServices() {
        instanceRegisterRepository.subscribeTotalGatewayServices((serviceDefinition, serviceInstances) -> {
            log.info("[Keveri-Cloud] 注册到网关的服务刷新了，其 ServiceId 为：{}", serviceDefinition.getServiceId());
            definitionDefinitionManager.addServiceInstance(serviceDefinition.getUniqueId(), serviceInstances);
            definitionDefinitionManager.putServiceDefinition(serviceDefinition.getUniqueId(), serviceDefinition);
        });
    }
}
